package userlogic

import (
	"context"
	"fmt"
	"math/rand"
	"strconv"
	"time"

	jwtToken "gitee.com/liuxuezhan/ar-platform/jwttoken"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/internal/dao/model"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/internal/dao/schema"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/internal/svc"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/login_rpc"
	config "gitee.com/liuxuezhan/ar-platform/login-rpc/pkg/code"
	re "gitee.com/liuxuezhan/ar-platform/login-rpc/pkg/redis_utils"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/pkg/tool"
	"github.com/zeromicro/go-zero/core/logc"
	"github.com/zeromicro/go-zero/core/logx"
)

type LoginAdminLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewLoginAdminLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginAdminLogic {
	return &LoginAdminLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *LoginAdminLogic) LoginAdmin(in *login_rpc.LoginAdminRequest) (*login_rpc.LoginAdminResponse, error) {
	var commonResp login_rpc.CommonResp
	if in.Account == "" || in.Password == "" {
		commonResp.Code = config.ParameterError
		commonResp.Message = "account or password is empty"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	if in.Ip == "" {
		commonResp.Code = config.ParameterError
		commonResp.Message = "empty login IP"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	if in.Source == "" {
		commonResp.Code = config.ParameterError
		commonResp.Message = "empty login Source"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}
	user, _ := model.NewAdminUserModel(l.ctx, l.svcCtx.Db).GetAdminUserByAccount(in.Account)
	if user.Id == 0 {
		commonResp.Code = config.ParameterError
		commonResp.Message = "no such account"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	if user.UserStatus != 0 {
		commonResp.Code = config.BasicError
		commonResp.Message = "user has been disabled"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	if HashPassword(in.Password) != user.Password {
		commonResp.Code = config.ParameterError
		commonResp.Message = "mismatched account or password"
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	// 谷歌验证
	if in.GoogleCode != "" {
		if user.IsOpenGoogle == 1 {
			if in.GoogleCode == "" {
				commonResp.Code = config.ParameterError
				commonResp.Message = "google auth code is required"
				return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
			}
			i, _ := strconv.ParseUint(in.GoogleCode, 10, 32)
			err := tool.CheckGoogleAuthCode(uint32(i), user.GoogleCode)
			if err != nil {
				commonResp.Code = config.ParameterError
				commonResp.Message = fmt.Sprintf("CheckGoogleAuthCode error: %v", err)
				return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
			}
		}
	}

	const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	sign := make([]byte, 10)
	for i := range sign {
		sign[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	// 用户id与平台组合生成token
	encrypt, _, err := jwtToken.Generate2Token(user.Id, in.Source, in.Business, string(sign), true, user.Nickname)
	if err != nil {
		commonResp.Code = config.TokenError
		commonResp.Message = fmt.Sprintf("Generate2Token error: %v", err)
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	// 查询该平台token是否存在，存在则更新，不存在则插入
	db := l.svcCtx.Db.Begin()
	id, _ := model.NewAdminLoginToken(l.ctx, db).GetAdminUserLoginTokenByUserIdAndSource(user.Id, in.Source, in.Business)
	if id > 0 {
		err = model.NewAdminLoginToken(l.ctx, db).UpdateAdminUserLoginToken(id, string(sign), user.Id)
		if err != nil {
			db.Rollback()
			commonResp.Code = config.DBError
			commonResp.Message = fmt.Sprintf("UpdateAdminUserLoginToken error: %v", err)
			return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
		}
	} else {
		var adminLoginToken schema.AdminLoginToken
		adminLoginToken.UserId = user.Id
		adminLoginToken.Source = in.Source
		adminLoginToken.Sign = string(sign)
		adminLoginToken.Business = in.Business
		err = model.NewAdminLoginToken(l.ctx, db).InsertAdminUserLoginToken(&adminLoginToken)
		if err != nil {
			db.Rollback()
			commonResp.Code = config.DBError
			commonResp.Message = fmt.Sprintf("InsertAdminUserLoginToken error: %v", err)
			return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
		}
	}

	var userUpdate schema.AdminUser
	userUpdate.Id = user.Id
	userUpdate.LoginAt = time.Now().Unix()
	userUpdate.LoginIp = in.Ip
	userUpdate.LoginNumber = user.LoginNumber + 1
	userUpdate.LoginStatus = 1

	if user.IsOpenGoogle == 1 && user.IsBindingGoogle == 0 {
		userUpdate.IsBindingGoogle = 1
	}

	err = model.NewAdminUserModel(l.ctx, db).UpdateAdminUser(userUpdate)
	if err != nil {
		db.Rollback()
		commonResp.Code = config.DBError
		commonResp.Message = fmt.Sprintf("UpdateAdminUser error: %v", err)
		return &login_rpc.LoginAdminResponse{CommonResp: &commonResp}, nil
	}

	err = re.SetTokenRedis(l.ctx, l.svcCtx.Config.RedisConfig, user.Id, true, in.Business, in.Source, string(sign))
	logc.Error(l.ctx, "SetTokenRedis,err:", err)

	db.Commit()
	return &login_rpc.LoginAdminResponse{UserId: user.Id, CommonResp: &commonResp, Token: encrypt}, nil

}
